﻿using System;
using System.Drawing;
using System.Collections;
using System.ComponentModel;
using System.Data;
using System.Runtime.InteropServices;

namespace TrainTicketsRobot
{
    class AspriseOCR
    {
        [DllImport("AspriseOCR.dll", EntryPoint = "OCR", CallingConvention = CallingConvention.Cdecl)]
        public static extern IntPtr OCR(string file, int type);

        [DllImport("AspriseOCR.dll", EntryPoint = "OCRpart", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr OCRpart(string file, int type, int startX, int startY, int width, int height);

        [DllImport("AspriseOCR.dll", EntryPoint = "OCRBarCodes", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr OCRBarCodes(string file, int type);

        [DllImport("AspriseOCR.dll", EntryPoint = "OCRpartBarCodes", CallingConvention = CallingConvention.Cdecl)]
        static extern IntPtr OCRpartBarCodes(string file, int type, int startX, int startY, int width, int height);

        public static string OCRBitmap(Bitmap img)
        {
            string filename = System.Windows.Forms.Application.StartupPath + VerificationCodeBaseDir + "4.bmp";
            img.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);


            int DgGrayValue = GetDgGrayValue(ref img);
            ClearNoise(DgGrayValue, 1,ref img);
            ClearNoise(DgGrayValue, ref img);
            filename = System.Windows.Forms.Application.StartupPath + VerificationCodeBaseDir + "5.bmp";
            img.Save(filename, System.Drawing.Imaging.ImageFormat.Jpeg);


            string VerifiCode = Marshal.PtrToStringAnsi(OCR(filename, -1));
            return VerifiCode;
        }

        /// 
        /// 得到灰度图像前景背景的临界值 最大类间方差法，yuanbao,2007.08
        /// 
        /// 前景背景的临界值
        public static int GetDgGrayValue(ref Bitmap bmpobj)
        {
            int[] pixelNum = new int[256]; //图象直方图，共256个点
            int n, n1, n2;
            int total; //total为总和，累计值
            double m1, m2, sum, csum, fmax, sb; //sb为类间方差，fmax存储最大方差值
            int k, t, q;
            int threshValue = 1; // 阈值
            //生成直方图
            for (int i = 0; i < bmpobj.Width; i++)
            {
                for (int j = 0; j < bmpobj.Height; j++)
                {
                    //返回各个点的颜色，以RGB表示
                    pixelNum[bmpobj.GetPixel(i, j).R]++; //相应的直方图加1
                }
            }
            //直方图平滑化
            for (k = 0; k <= 255; k++)
            {
                total = 0;
                for (t = -2; t <= 2; t++) //与附近2个灰度做平滑化，t值应取较小的值
                {
                    q = k + t;
                    if (q < 0) //越界处理
                        q = 0;
                    if (q > 255)
                        q = 255;
                    total = total + pixelNum[q]; //total为总和，累计值
                }
                pixelNum[k] = (int)((float)total / 5.0 + 0.5); //平滑化，左边2个+中间1个+右边2个灰度，共5个，所以总和除以5，后面加0.5是用修正值
            }
            //求阈值
            sum = csum = 0.0;
            n = 0;
            //计算总的图象的点数和质量矩，为后面的计算做准备
            for (k = 0; k <= 255; k++)
            {
                sum += (double)k * (double)pixelNum[k]; //x*f(x)质量矩，也就是每个灰度的值乘以其点数（归一化后为概率），sum为其总和
                n += pixelNum[k]; //n为图象总的点数，归一化后就是累积概率
            }

            fmax = -1.0; //类间方差sb不可能为负，所以fmax初始值为-1不影响计算的进行
            n1 = 0;
            for (k = 0; k < 256; k++) //对每个灰度（从0到255）计算一次分割后的类间方差sb
            {
                n1 += pixelNum[k]; //n1为在当前阈值遍前景图象的点数
                if (n1 == 0) { continue; } //没有分出前景后景
                n2 = n - n1; //n2为背景图象的点数
                if (n2 == 0) { break; } //n2为0表示全部都是后景图象，与n1=0情况类似，之后的遍历不可能使前景点数增加，所以此时可以退出循环
                csum += (double)k * pixelNum[k]; //前景的“灰度的值*其点数”的总和
                m1 = csum / n1; //m1为前景的平均灰度
                m2 = (sum - csum) / n2; //m2为背景的平均灰度
                sb = (double)n1 * (double)n2 * (m1 - m2) * (m1 - m2); //sb为类间方差
                if (sb > fmax) //如果算出的类间方差大于前一次算出的类间方差
                {
                    fmax = sb; //fmax始终为最大类间方差（otsu）
                    threshValue = k; //取最大类间方差时对应的灰度的k就是最佳阈值
                }
            }
            return threshValue;
        }

        /// 
        /// 去掉杂点（适合杂点/杂线粗为1）
        /// 
        /// 背前景灰色界限
        /// 
        public static void ClearNoise(int dgGrayValue, int MaxNearPoints, ref Bitmap bmpobj)
        {
            Color piexl;
            int nearDots = 0;
            //逐点判断
            for (int i = 0; i < bmpobj.Width; i++)
                for (int j = 0; j < bmpobj.Height; j++)
                {
                    piexl = bmpobj.GetPixel(i, j);
                    if (piexl.R < dgGrayValue)
                    {
                        nearDots = 0;
                        //判断周围8个点是否全为空
                        if (i == 0 || i == bmpobj.Width - 1 || j == 0 || j == bmpobj.Height - 1) //边框全去掉
                        {
                            bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                        }
                        else
                        {
                            if (bmpobj.GetPixel(i - 1, j - 1).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i, j - 1).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i + 1, j - 1).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i - 1, j).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i + 1, j).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i - 1, j + 1).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i, j + 1).R < dgGrayValue) nearDots++;
                            if (bmpobj.GetPixel(i + 1, j + 1).R < dgGrayValue) nearDots++;
                        }

                        if (nearDots < MaxNearPoints)
                            bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255)); //去掉单点 && 粗细小3邻边点
                    }
                    else //背景
                        bmpobj.SetPixel(i, j, Color.FromArgb(255, 255, 255));
                }
        }

        /// 
        /// 3×3中值滤波除杂，yuanbao,2007.10
        /// 
        /// 
        public static void ClearNoise(int dgGrayValue, ref Bitmap bmpobj)
        {
            int x, y;
            byte[] p = new byte[9]; //最小处理窗口3*3
            byte s;
            int i, j;

            //--!!!!!!!!!!!!!!下面开始窗口为3×3中值滤波!!!!!!!!!!!!!!!!
            for (y = 1; y < bmpobj.Height - 1; y++) //--第一行和最后一行无法取窗口
            {
                for (x = 1; x < bmpobj.Width - 1; x++)
                {
                    //取9个点的值
                    p[0] = bmpobj.GetPixel(x - 1, y - 1).R;
                    p[1] = bmpobj.GetPixel(x, y - 1).R;
                    p[2] = bmpobj.GetPixel(x + 1, y - 1).R;
                    p[3] = bmpobj.GetPixel(x - 1, y).R;
                    p[4] = bmpobj.GetPixel(x, y).R;
                    p[5] = bmpobj.GetPixel(x + 1, y).R;
                    p[6] = bmpobj.GetPixel(x - 1, y + 1).R;
                    p[7] = bmpobj.GetPixel(x, y + 1).R;
                    p[8] = bmpobj.GetPixel(x + 1, y + 1).R;
                    //计算中值
                    for (j = 0; j < 5; j++)
                    {
                        for (i = j + 1; i < 9; i++)
                        {
                            if (p[j] > p[i])
                            {
                                s = p[j];
                                p[j] = p[i];
                                p[i] = s;
                            }
                        }
                    }
                    // if (bmpobj.GetPixel(x, y).R < dgGrayValue)
                    bmpobj.SetPixel(x, y, Color.FromArgb(p[4], p[4], p[4])); //给有效值付中值
                }
            }
        }

        public static string VerificationCodeBaseDir = "/verificationcode/";
    }
}
